import axios from 'axios';
import { getToken, setToken } from './Storage.js';
import router from '../router.js';
import Utils from './Utils.js';
import { useNotificationStore } from '@/stores/notification.js';

const baseURL = import.meta.env.VITE_APP_DEV+"/api";
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8';

const service = axios.create({
    baseURL: baseURL,
    timeout: 20000
});

service.interceptors.request.use(config => {
    if (config.token) { // 自定义配置项，用于标记需要token的请求
        config.headers['Authorization'] = `Bearer ${getToken()}`;
    }
    return config;
}, error => {
    console.error('request error:', error);
    return Promise.reject(error);
});

service.interceptors.response.use(res => {
    const { config: { download }, data } = res;
    if (download) return data;

    const { code, msg } = data;
    if (code === 200) return data;

    const notificationStore = useNotificationStore();
    switch (code) {
        case 401:
            setToken(null);
            notificationStore.error('认证失败，请重新登录');
            requestAnimationFrame(() => router.push('/login'));
            break;
        default:
            notificationStore.error(msg || '操作失败');
            break;
    }
    return Promise.reject(msg);
}, error => {
    let message = "服务器开小差了";
    console.error('response error:', error);

    if (error.response && error.response.data && typeof error.response.data.msg === 'string') {
        message = error.response.data.msg;
    } else if (error.message) {
        if (error.message.includes('timeout')) {
            message = '请求超时，请检查您的网络连接';
        } else if (error.message.includes('Network Error')) {
            message = '网络连接异常，无法连接到服务器';
        }
    }

    const notificationStore = useNotificationStore();
    notificationStore.error(message);

    if (error.response?.status === 401) {
        setToken(null);
        requestAnimationFrame(() => router.push('/login'));
    }

    return Promise.reject(error);
});

export default {
    get(url, params = {}) {
        const cloneData = JSON.parse(JSON.stringify(params));
        Object.keys(cloneData).forEach(key => {
            if (params[key] instanceof Date) {
                cloneData[key] = Utils.convertDateToString(params[key]);
            }
        });
        return service.get(url, {
            params: cloneData,
            token: true
        });
    },
    getWithoutToken(url, params) {
        return service.get(url, {
            params
        });
    },
    post(url, data = {}) {
        const cloneData = JSON.parse(JSON.stringify(data));
        Object.keys(cloneData).forEach(key => {
            if (data[key] instanceof Date) {
                cloneData[key] = Utils.convertDateToString(data[key]);
            }
        });
        return service.post(url, cloneData, {token: true});
    },
    postWithoutToken(url, data = {}) {
        return service.post(url, data, {token: false});
    },
    put(url, data = {}) {
        const cloneData = JSON.parse(JSON.stringify(data));
        Object.keys(cloneData).forEach(key => {
            if (data[key] instanceof Date) {
                cloneData[key] = Utils.convertDateToString(data[key]);
            }
        });
        return service.put(url, cloneData, {token: true});
    },
    delete(url, ids) {
        let requestUrl = url;
        let config = { token: true };
        if (Array.isArray(ids) && ids.length > 0) {
            requestUrl = url + ids.join(',');
        } else if (typeof ids === 'object' && ids !== null) {
            config.params = ids;
        }
        return service.delete(requestUrl, config);
    },
    downloadFile(url, params = {}, fileName) {
        return (service.get(url, {
            responseType: 'blob',
            token: true,
            download: true,
            params
        }).then(res => {
            const link = document.createElement('a');
            link.href = URL.createObjectURL(res);
            link.setAttribute('download', fileName || Utils.getFileNameFromURL(url));
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
        }));
    },
    upload(url, formData, config = {}) {
        return service.post(url, formData, {
            ...config,
            token: true,
            headers: {
                'Content-Type': 'multipart/form-data'
            }
        });
    },
    previewFile(url) {
        return service.get(url, {
            responseType: 'blob',
            token: true,
            download: true
        });
    },
    getConfigByKey(key) {
        return service.get(`/system/config/configKey/${key}`);
    },
    stream(url, data, {onChunk}) {
        return new Promise(async (resolve, reject) => {
            try {
                const fullUrl = new URL(url, baseURL).href;

                const response = await fetch(fullUrl, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'Authorization': `Bearer ${getToken()}`
                    },
                    body: JSON.stringify(data)
                });

                if (!response.ok) {
                    const errorText = await response.text();
                    throw new Error(`服务器错误: ${response.status} - ${errorText}`);
                }

                const reader = response.body.getReader();
                const decoder = new TextDecoder();

                while (true) {
                    const {done, value} = await reader.read();
                    if (done) {
                        resolve();
                        break;
                    }
                    const chunk = decoder.decode(value, {stream: true});
                    if (onChunk) {
                        onChunk(chunk);
                    }
                }
            } catch (error) {
                console.error("流式请求封装中捕获到错误:", error);
                reject(error);
            }
        });
    },
    /**
     * [新增] 用于文件上传的流式请求 (例如 AI 识图)
     * @param {string} url - 请求的 API 地址
     * @param {FormData} formData - 包含文件和其他数据的 FormData 对象
     * @param {object} callbacks - 包含事件回调函数的对象
     * @param {function(string): void} callbacks.onData - 每次收到数据片段时的回调
     * @param {function(): void} [callbacks.onDone] - 流结束时的回调
     * @param {function(Error): void} [callbacks.onError] - 发生错误时的回调
     */
    async streamUpload(url, formData, { onData, onDone, onError }) {
        try {
            // 必须使用 fetch API 来处理响应流。axios 在浏览器中不擅长此道。
            // 1. 构建完整的请求URL
            const fullUrl = new URL(url, baseURL).href;

            // 2. 发起 fetch 请求
            const response = await fetch(fullUrl, {
                method: 'POST',
                body: formData, // 直接传递 FormData
                headers: {
                    // 不需要手动设置 'Content-Type': 'multipart/form-data'
                    // 浏览器在发送 FormData 时会自动设置正确的类型和 boundary
                    'Authorization': `Bearer ${getToken()}` // 从您的 storage.js 获取 token
                },
            });

            // 3. 检查响应状态
            if (!response.ok) {
                // 如果服务器返回错误，尝试读取错误信息
                const errorText = await response.text();
                throw new Error(`服务器错误: ${response.status} - ${errorText}`);
            }

            // 4. 处理响应流
            const reader = response.body.getReader();
            const decoder = new TextDecoder();

            while (true) {
                const { done, value } = await reader.read();
                if (done) {
                    if (onDone) onDone(); // 流结束，调用 onDone 回调
                    break;
                }

                // 解码收到的数据块
                const chunk = decoder.decode(value, { stream: true });

                // 解析 SSE (Server-Sent Events) 格式
                // 后端发送的格式是 "data: {json_chunk}\n\n"
                const lines = chunk.split('\n\n');
                for (const line of lines) {
                    if (line.startsWith('data: ')) {
                        const jsonData = line.substring(5).trim();
                        if (onData) onData(jsonData); // 将纯净的 JSON 片段传递给 onData 回调
                    }
                }
            }
        } catch (error) {
            console.error("streamUpload 封装中捕获到错误:", error);
            if (onError) onError(error); // 发生任何错误，调用 onError 回调
        }
    }
};